home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / adult_ed / rp / rp.c < prev    next >
C/C++ Source or Header  |  1995-05-02  |  17KB  |  616 lines

  1. /*
  2.    rp
  3.  
  4.    Running Performance Predictor
  5.    by Joseph M. Knapp
  6.  
  7. */
  8.  
  9. #include <stdio.h>
  10. #include <math.h>
  11.  
  12. #define MAXEVENTS 50   /* maximum # of events to analyze */
  13. #define MAXSTRING 15   /* maximum length of time string */
  14. #define MAXUSTR 20     /* maximum length of distance-unit strings */
  15. #define MILE 1609      /* meters per mile */
  16. #define MAXU   50      /* maximum number of distance units */
  17. #define UNK -1         /* unknown string flag */
  18. #define AMB -2         /* ambiguous string flag */
  19. #define LOWCORR .90    /* low-correlation message threshold */
  20. #define MAXV0  12      /* maximum v0 before error warning */
  21. #define MINV1  -4      /* minimum v1 before error warning */
  22. #define MAXLINE 80     /* maximum line length in event file */
  23. #define TRUE   1
  24. #define FALSE  0
  25.  
  26. /* this structure will be used to hold the unit/value pairs */
  27. struct ascfloat {
  28.    char string[MAXUSTR] ;  /* ascii representation of unit */
  29.    float value ;           /* value of unit (meters) */
  30.    } ;
  31.  
  32. /* this structure will hold an event read in from the event file */
  33. struct event {
  34.    float s ;   /* distance of event */
  35.    float t ;   /* time of event */
  36.    } ;
  37.  
  38. /* this structure will hold the predicted performances */
  39. struct pp {
  40.    float logs ; /* log10 of prediction distance */
  41.    float v ;    /* predicted average speed */
  42.    } ;
  43.  
  44. /* uval() - returns the  value of a distance-unit string */
  45. float uval(tunit,utypes,no)
  46. char tunit[] ;              /* string containing test unit specification */
  47. struct ascfloat utypes[] ;  /* .string, .value pairs */
  48. int no ;                    /* number of pairs in structure */
  49. {
  50.    int uind ; /* index into utypes structure */
  51.  
  52.    uind = strmtch(tunit,utypes,no) ; /* returns index of match or err code */
  53.    if (uind == UNK)
  54.    {
  55.       fprintf(stderr,"distance-file error: '%s' unknown\n",tunit) ;
  56.       exit(0) ;
  57.    }
  58.    else if (uind == AMB)
  59.    {
  60.       fprintf(stderr,"distance-file error: '%s' ambiguous\n",tunit) ;
  61.       exit(0) ;
  62.    }
  63.    else return(utypes[uind].value) ;  /* successful match, return value */
  64. }
  65.  
  66. /* realtime() take a time string (e.g. 8:20:13) and returns the value in sec */
  67. double realtime(str)
  68. char *str ;  /* time string */
  69. {
  70.    char *sptr ;              /* pointer into substring */
  71.    char substr[MAXSTRING] ;  /* substring */
  72.    static int level ;        /* 0=sec 1=min 2=hr */
  73.    static float cumtime ;    /* cumulative time */
  74.    double realtime() ;       /* recursive */
  75.    float tfield ;            /* value of time field */
  76.  
  77.    sptr = substr ;  /* point to substring (now empty) */
  78.  
  79.    level = 0 ;
  80.    cumtime = 0 ;
  81.  
  82.    /* copy time string into substr[] until ':' or end of string */
  83.    while ((*sptr = *str) != '\0' &&
  84.            *str !=  ':' ) 
  85.    {
  86.       sptr++ ;
  87.       str++ ;
  88.    }
  89.  
  90.    /* if now pointing to ':' ther are more fields, call again */
  91.    if (*sptr == ':') cumtime = realtime(++str) ;
  92.  
  93.    /* bottomed out, ripple back */
  94.    *sptr = '\0' ;
  95.    if (sscanf(substr,"%f",&tfield))
  96.    {
  97.       return(cumtime + tfield * pow((double)60,(double)(level++))) ;
  98.    }
  99.    else
  100.    {
  101.       fprintf(stderr,"event-file error: bad time string\n") ;
  102.       exit(0) ;
  103.    }
  104. }
  105.  
  106. /* return TRUE if line is not a comment */
  107. int comf(tline)
  108. char *tline ;
  109. {
  110.    char ch ;
  111.  
  112.    sscanf(tline," %c ",&ch) ;
  113.  
  114.    if (ch == '*') return(FALSE) ;
  115.       else return(TRUE) ;
  116. }
  117.  
  118. /* return TRUE if line is not all whitespace */
  119. int notwhite(tline)
  120. char *tline ;
  121. {
  122.    int wflg ;
  123.    int ich ;
  124.  
  125.    wflg = FALSE ;
  126.    for (ich = 0 ; ich < strlen(tline) ; ich++)
  127.       if (!isspace(*(tline+ich))) wflg = TRUE ;
  128.    return(wflg) ;
  129. }
  130.  
  131. usage()
  132. {
  133.       printf("\nusage:\n") ;
  134.       printf("rp [-q|-12][-d <dist-file>][-u <unit-file>] [<event-file>]\n") ;
  135.  
  136.       printf("    where:\n") ;
  137.       printf("       <events> is a file of events:<distance><time> pairs\n") ;
  138.       printf("           e.g., 10 k  36:16   * this is a comment\n") ;
  139.       printf("       <unit-file> is a file of known distance units\n") ;
  140.       printf("           where a unit is a <string> <meters> pair\n") ;
  141.       printf("           e.g., miles 1609\n") ;
  142.       printf("           (default file: dunits)\n") ;
  143.       printf("       <dist-file> is a file of prediction distances\n") ;
  144.       printf("           where a distance is a <number> <unit> pair\n") ;
  145.       printf("           e.g., 0.5 marathon\n") ;
  146.       printf("           (default file: dlist)\n") ;
  147.       printf("       -12 -> simulate a 12-minute fitness test\n") ;
  148.       printf("       -q  -> print list of runs of same quality as a\n") ;
  149.       printf("              specified standard run\n\n") ;
  150.       printf("\n   rp without args reads events from keyboard\n") ;
  151.       exit(0) ;
  152. }
  153.  
  154. main(argc,argv)
  155. int argc ;
  156. char *argv[] ;
  157. {
  158.  
  159.    FILE *fp, *fopen() ;
  160.  
  161.    struct event events[MAXEVENTS] ;    /* distance/time pairs */
  162.    struct pp perfline[MAXEVENTS] ;     /* speed/log-distance pairs */
  163.  
  164.    float vbar ;                  /* average speed of events */
  165.    float v0 ;
  166.    float sbar ;                  /* average ditance of events */
  167.    char time[MAXSTRING] ;        /* time string xx:xx:xx.x */
  168.    char unit[MAXSTRING] ;        /* distance unit */
  169.    float scalar ;                /* scalar distance */
  170.    int eventno ;                 /* event counter */
  171.    int ev ;
  172.    int stdineof ;
  173.    int nunits ;
  174.    int option, optind ;
  175.    int age, isex ;
  176.    char sex[10] ;
  177.    float cvar ;
  178.    float var1 ;
  179.    float var2 ;
  180.    float m12, m21 ;
  181.    float b12, b21 ;
  182.    float rho ;
  183.    float s, v, t ;
  184.    float smx, smn ;
  185.  
  186.    char ufile[50], dfile[50], pfile[50] ;
  187.    char evline[MAXLINE] ;
  188.  
  189.    float uval() ;
  190.    double realtime() ;
  191.  
  192.    struct ascfloat utypes[MAXU] ;
  193.  
  194.    sprintf(ufile,"%s","dunits") ;
  195.    sprintf(dfile,"%s","dlist") ;
  196.  
  197.    /* process command-line options */
  198.    option = 0 ;
  199.    for (optind = 1 ; optind < argc-1 ; optind++) 
  200.    {
  201.       if (strcmp(argv[optind],"-12" ) == 0) option = 1 ;
  202.       else if (strcmp(argv[optind],"-q" ) == 0) option = 2 ;
  203.       else if (strcmp(argv[optind],"-u") == 0)
  204.          sprintf(ufile,"%s",argv[++optind]) ;
  205.       else if (strcmp(argv[optind],"-d") == 0)
  206.          sprintf(dfile,"%s",argv[++optind]) ;
  207.       else if (strcmp(argv[optind],"-h") == 0)
  208.          usage() ;
  209.  
  210.       else
  211.       {
  212.          printf("unknown option '%s'\n",argv[optind]) ;
  213.          usage() ;
  214.          exit(0) ;
  215.       }
  216.    }
  217.  
  218.    nunits = uload(ufile,utypes) ; /* load unit file into 'utypes' struct */
  219.  
  220.    /* get fp of event file */
  221.    if (argc > 1)
  222.    {
  223.       sprintf(pfile,"%s",argv[argc-1]) ;
  224.       fp = fopen(pfile,"r") ;
  225.       if (fp == NULL)
  226.       {
  227.          fprintf(stderr,"event-file error: can't open '%s'\n",pfile) ;
  228.          exit(0) ;
  229.       }
  230.    }
  231.    else
  232.    {
  233.       fp=stdin ;  /* only one arg, use stdin */
  234.       sprintf(pfile,"%s","stdin") ;
  235.    }
  236.  
  237.    /* get events and store them in 'events' struct */
  238.    eventno = 0 ;
  239.    stdineof = 1 ;  /* will go to 0 on empty line from stdin */
  240.    if (fp == stdin)
  241.       printf("enter events: <distance> <time> , end with empty line\n") ;
  242.    while ((fp != stdin || stdineof) && fgets(evline,MAXLINE,fp) != NULL)
  243.    {
  244.       /* skip if comment */
  245.       if(comf(evline))
  246.       {
  247.          if (*evline != '\n')  /* only do if length > 0 */
  248.          {
  249.             /* read event line and check for scanf format error */
  250.             if (notwhite(evline))  /* is not all whitespace? */
  251.             {
  252.                if (sscanf(evline," %f %s %s ",&scalar,unit,time))
  253.                {
  254.                   events[eventno].s = scalar * uval(unit,utypes,nunits) ;
  255.                   events[eventno].t = realtime(time) ;
  256.                   eventno++ ;
  257.                }
  258.                else
  259.                {
  260.                   fprintf(stderr,"event-file error: field 1 not a number\n") ;
  261.                   exit(0) ;
  262.                }
  263.             }
  264.          }
  265.          else stdineof = 0 ;  /* if length = 0 terminate stdin */
  266.       }
  267.    }
  268.    if (fp != stdin) fclose(fp) ;
  269.  
  270.    if (eventno < 2)
  271.    {
  272.       fprintf(stderr,"event-file error: not enough events\n") ;
  273.       exit(0) ;
  274.    }
  275.  
  276.    smx = 0 ;
  277.    smn = 1e6 ;
  278.    for (ev = 0 ; ev < eventno ; ev++)
  279.    {
  280.       s = events[ev].s ;
  281.       if (s < smn) smn = s ;
  282.       if (s > smx) smx = s ;
  283.    }
  284.    if (smx - smn == 0)
  285.    {
  286.       fprintf(stderr,"event-file error: all events are same distance\n") ;
  287.       exit(0) ;
  288.    }
  289.  
  290.    for (ev = 0; ev < eventno; ev++)
  291.    {
  292.       perfline[ev].v = events[ev].s/events[ev].t ;
  293.       perfline[ev].logs = log10(events[ev].s) ;
  294.    }
  295.  
  296.    vbar = 0 ;
  297.    sbar = 0 ;
  298.    for (ev = 0 ; ev < eventno ; ev++)
  299.    {
  300.       vbar += perfline[ev].v ;
  301.       sbar += perfline[ev].logs ;
  302.    }
  303.    vbar = vbar/eventno ;
  304.    sbar = sbar/eventno ;
  305.  
  306.    cvar = 0 ;
  307.    for (ev = 0 ; ev < eventno ; ev++)
  308.       cvar += (perfline[ev].v - vbar) * (perfline[ev].logs - sbar) ;
  309.    cvar = cvar/(eventno - 1) ;
  310.  
  311.    var1 = 0 ;
  312.    var2 = 0 ;
  313.    for (ev = 0 ; ev < eventno ; ev++)
  314.    {
  315.       var1 += (perfline[ev].logs - sbar) * (perfline[ev].logs - sbar) ;
  316.       var2 += (perfline[ev].v - vbar) * (perfline[ev].v - vbar) ;
  317.    }
  318.    var1 = var1/(eventno - 1) ;
  319.    var2 = var2/(eventno - 1) ;
  320.  
  321.    m12 = var2/cvar ;
  322.    b12 = vbar - m12 * sbar ;
  323.    m21 = cvar/var1 ;
  324.    b21 = vbar - m21 * sbar ;
  325.  
  326.    rho = cvar/(sqrt(var1)*sqrt(var2)) ;
  327.  
  328.    switch(option) {
  329.    case 0:
  330.       grid(b21,m21,dfile,utypes,nunits,rho,pfile,eventno) ;
  331.       break ;
  332.  
  333.    case 1:
  334.       printf("\n>>> 12-Minute Fitness Test (after Dr. Kenneth Cooper) <<<\n") ;
  335.       printf("\n") ;
  336.  
  337.       do
  338.       {
  339.          printf("enter sex (m/f): ") ;
  340.          scanf("%s",sex) ;
  341.       }
  342.       while (sex[0] != 'm' && sex[0] !='f') ;
  343.  
  344.       if (sex[0] == 'm') isex=0 ;
  345.          else isex=1 ;
  346.  
  347.       do
  348.       {
  349.          printf("input age: ") ;
  350.          scanf("%d",&age) ;
  351.       }
  352.       while (age < 1 || age > 99) ;
  353.  
  354.       test12(b21,m21,isex,age) ;
  355.       break  ;
  356.  
  357.    case 2:
  358.       printf("Input standard run <distance> <time>: ") ;
  359.       scanf(" %f %s %s ", &scalar, unit, time) ;
  360.       t = realtime(time) ;
  361.       s = scalar * uval(unit,utypes,nunits) ;
  362.       v = s/t ;
  363.       v0 = b21 + m21*log10(s) - v ;
  364.       grid(b21-v0,m21,dfile,utypes,nunits,rho,pfile,eventno) ;
  365.    }
  366. }
  367.  
  368. grid(b,m,dfile,utypes,nunits,rho,pfile,no)
  369. char dfile[] ;
  370. struct ascfloat utypes[] ;
  371. int nunits ;
  372. float b,m,rho ;
  373. char pfile[] ;
  374. int no ;
  375. {
  376.    FILE *fp, *fopen() ;
  377.    float s,v,t ;
  378.    float scalar ;
  379.    char pace[20],
  380.         time[20] ;
  381.    char unit[20] ;
  382.    float uval() ;
  383.    int scanres ;
  384.  
  385.    fp = fopen(dfile,"r") ;  /* open distance-list file */
  386.    if (fp == NULL)
  387.    {
  388.       fprintf(stderr,"distance-file error: can't open '%s'\n",dfile) ;
  389.       exit(0) ;
  390.    }
  391.  
  392.    printf("\nanalysis of file '%s'  (%d events):\n",pfile,no) ;
  393.    printf("\nmodel equation: v =%5.2f%6.2f*log10(s)",b,m) ;
  394.    if (no > 2) printf("   correlation ~ %2.0f\n",fabs(rho*100.)) ;
  395.       else printf("\n") ;
  396.  
  397.    if ( b > MAXV0 || m > 0 || m < MINV1 )
  398.       printf("probable bogus model -- unusual parameters\n") ;
  399.  
  400.    if (fabs(rho) < LOWCORR)
  401.       printf("low correlation\n") ;
  402.  
  403.    printf("\n") ;
  404.  
  405.    printf("%-19s %10s %10s %10s\n"," ",
  406.           "time","speed","pace") ;
  407.    printf("%-19s %10s %10s %10s\n","distance",
  408.           "hh:mm:ss","meters/s","min/mile") ;
  409.    printf("%-19s %10s %10s %10s\n","-----------------",
  410.           "--------","--------","--------") ;
  411.    while ((scanres = fscanf(fp," %f %s ",&scalar,unit)) != EOF )
  412.      {
  413.       if (!scanres)
  414.       {
  415.          fprintf(stderr,"distance-file error: unrecognizable distance\n") ;
  416.          exit(0) ;
  417.       }
  418.  
  419.       s = scalar * uval(unit,utypes,nunits) ;
  420.       v = b + m*log10(s) ;
  421.       t = s/v ;
  422.  
  423.       tstr(MILE/v,pace) ;
  424.       tstr(t,time) ;
  425.  
  426.       if (fmod(scalar,1.0) > 0)
  427.       printf("%6.1f %-12s %10s %10.2f %10s\n",
  428.              scalar,unit,time,v,pace) ;
  429.       else
  430.       printf("%6.0f %-12s %10s %10.2f %10s\n",
  431.              scalar,unit,time,v,pace) ;
  432.        
  433.       }
  434.    printf("\n") ;
  435.    fclose(fp) ;
  436.  
  437. }
  438.  
  439. tstr(t,str)
  440. float t ;
  441. char *str ;
  442. {
  443.    int h,m,s ;
  444.    int it ;
  445.    it = t ;
  446.    h = it / 3600 ;
  447.    m = (it/60)-h*60 ;
  448.    s = it - h*3600 - m*60 ;
  449.  
  450.    if (h>0)
  451.       sprintf(str,"%2d:%02d:%02d",h,m,s) ;
  452.    else {
  453.       if (m>0)
  454.          sprintf(str,"%2d:%02d",m,s) ;
  455.       else
  456.       sprintf(str,"%2d",s) ;
  457.       }
  458. }
  459.  
  460. /* return position of matching string or UNK (unknown) or AMB (ambiguous) */
  461. strmtch(ustr,utypes,no)
  462. char *ustr ; /* test string */
  463. struct ascfloat utypes[] ; /* reference unit strings (& values) */
  464. int no ; /* number of reference strings */
  465. {
  466.    int m, nmatch ;
  467.    int word, len, imtch ;
  468.  
  469.    nmatch = 0 ;
  470.    word = 0 ;
  471.    len = strlen(ustr) ;
  472.  
  473.    do
  474.    {
  475.       m = strncmp(ustr,utypes[word++].string,len) ;
  476.       if (m == 0)
  477.       {
  478.          nmatch++ ;
  479.          imtch = word - 1 ;
  480.       }
  481.    }
  482.    while (word < no) ;
  483.  
  484.    if (nmatch > 1) word = AMB ;
  485.    else if (nmatch == 0) word = UNK ;
  486.    else word = imtch ;
  487.  
  488.    return(word) ;
  489. }
  490.  
  491.  
  492. int uload(ufile,utypes)
  493. char ufile[] ; /* file containing <string> <meters> pairs */
  494. struct ascfloat utypes[] ; /* to contain those pairs */
  495. {
  496.    int i ;
  497.    int scanres ;
  498.    FILE *fp, *fopen() ;
  499.  
  500.    fp = fopen(ufile,"r") ;
  501.    if (fp == NULL)
  502.    {
  503.       fprintf(stderr,"unit-file error: can't open '%s'\n",ufile) ;
  504.       exit(0) ;
  505.    }
  506.  
  507.    i = 0 ;
  508.    while ((scanres=fscanf(fp," %s %f ",utypes[i].string,&utypes[i].value))!=EOF)
  509.    {
  510.       i++ ;
  511.       if (!scanres)
  512.       {
  513.          fprintf(stderr,"unit-file error: illegal unit definition \n") ;
  514.          exit(0) ;
  515.       }
  516.    }
  517.  
  518.  
  519.    fclose(fp) ;
  520.  
  521.    if (i == 0)
  522.    {
  523.       fprintf(stderr,"unit-file error: no units recognized in '%s'\n",ufile) ;
  524.       exit(0) ;
  525.    }
  526.    return(i) ;
  527. }
  528.  
  529. test12(v0,v1,sex,age)
  530. float v0 ;     /* one-meter speed */
  531. float v1 ;   /* aerobic factor */
  532. int sex ;    /* 0=male 1=female */
  533. int age ;      /* years old */
  534. {
  535.    static float mu30[6] = { 0.00,1.00, 1.24, 1.49, 1.74, 3.5 } ;
  536.    static float mu40[6] = { 0.00,0.95, 1.14, 1.39, 1.64, 3.5 } ;
  537.    static float mu50[6] = { 0.00,0.85, 1.04, 1.29, 1.54, 3.5 } ;
  538.    static float mu99[6] = { 0.00,0.80, 0.99, 1.24, 1.49, 3.5 } ;
  539.    static float wu30[6] = { 0.00,0.95, 1.14, 1.34, 1.64, 3.5 } ;
  540.    static float wu40[6] = { 0.00,0.85, 1.04, 1.24, 1.54, 3.5 } ;
  541.    static float wu50[6] = { 0.00,0.75, 0.94, 1.14, 1.44, 3.5 } ;
  542.    static float wu99[6] = { 0.00,0.65, 0.84, 1.04, 1.34, 3.5 } ;
  543.    static float *man[4] = { mu30, mu40, mu50, mu99 } ;
  544.    static float *woman[4] = { wu30, wu40, wu50, wu99 } ;
  545.  
  546.    static float vo2tab[6] = { 0.00,25.0,33.7,42.5,51.5,105.0 } ;
  547.    static float stab[6] =  { 0,1.0,1.25,1.50,1.75,3.5 } ;
  548.  
  549.    int ageind ;
  550.    int level ;
  551.    int vind ;
  552.    float minv,maxv ;
  553.    float s ;
  554.    float maxvo2, x ;
  555.  
  556.    level = 0 ;
  557.  
  558.    ageind = age/10 - 2 ;
  559.    if (ageind < 0 ) ageind = 0 ;
  560.  
  561.    /* calculate 12-minute distance in miles */
  562.    s = 160 ;  /* 160 meters = 0.1 mile */
  563.    while (s/(v0+v1*log10(s)) < 720 )
  564.       s = s + 160 ;
  565.  
  566.    while (s/(v0 + v1*log10(s)) > 720 )
  567.       s = s - 16 ;
  568.  
  569.    /* convert meters to miles */
  570.    s = s/(MILE) ;
  571.  
  572.    /* find fitness level (1-5) */
  573.    if (sex == 0 ) /* woman */
  574.       while (woman[ageind][level++] < s) ;
  575.    else
  576.       while (man[ageind][level++] < s) ;
  577.  
  578.    level-- ; /* correct level */
  579.    /* interpolate to find max V02 */
  580.    vind = 0 ;
  581.    while(stab[vind] < s ) vind++;
  582.  
  583.    vind-- ;
  584.  
  585.    minv = vo2tab[vind] ;
  586.    maxv = vo2tab[vind + 1] ;
  587.  
  588.    x = (s - stab[vind])/(stab[vind+1]-stab[vind]) ;
  589.  
  590.    maxvo2 = minv + x*(maxv-minv) ;
  591.  
  592.  
  593.    printf("\nIn 12 minutes, you could run%5.2f miles.\n\n",s) ;
  594.    printf("Of very poor, poor, fair, good, and excellent,\n") ;
  595.    printf("your fitness level is " ) ; 
  596.    switch(level) {
  597.    case 1:
  598.       printf( "very poor.\n\n") ;
  599.       break ;
  600.    case 2:
  601.       printf( "poor.\n\n" );
  602.       break ;
  603.    case 3:
  604.       printf( "fair.\n\n" );
  605.       break ;
  606.    case 4:
  607.       printf( "good.\n\n" );
  608.       break ;
  609.    case 5:
  610.       printf( "excellent.\n\n") ;
  611.       break ;
  612.    }
  613.    printf("Your estimated maximum oxygen uptake (VO2max)\n") ; 
  614.    printf("is%5.1f ml/kg/min.\n\n", maxvo2) ;
  615. }
  616.